package edu.cuit.canary.core.cofig;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.time.Duration;
import java.util.concurrent.ThreadLocalRandom;

@Configuration
@EnableCaching
public class RedisConfig {

    @Bean
    public RedisTemplate<String, ?> redisTemplate(@Autowired RedisConnectionFactory factory){
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        //设置连接工厂
        redisTemplate.setConnectionFactory(factory);
        //key的序列化器:字符串序列化器
        redisTemplate.setKeySerializer(RedisSerializer.string());
        //value的序列化器
        var jackson2JsonRedisSerializer = getObjectJackson2JsonRedisSerializer();;

        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        return redisTemplate;
    }


    /**
     * 自定义缓存管理器
     */
    @Bean
    public CacheManager cacheManager(@Autowired RedisConnectionFactory redisConnectionFactory){
        var jackson2JsonRedisSerializer = getObjectJackson2JsonRedisSerializer();

        return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
                .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()
                        //.disableCachingNullValues() //不缓存null值(缓存穿透)
                        .prefixCacheNameWith("canary:")
                        .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()))
                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                        .entryTtl(Duration.ofSeconds(5000 * 60 + randomTTL()))) //给缓存的key添加随机时间

                .build();
    }

    private static Jackson2JsonRedisSerializer<Object> getObjectJackson2JsonRedisSerializer() {
        ObjectMapper om = new ObjectMapper();
        // 设置在反序列化时忽略在JSON字符串中存在，而在Java中不存在的属性
        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        // 解决jackson2无法反序列化LocalDateTime的问题
        om.registerModule(new JavaTimeModule());
        om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
        // 不存在的字段,不被序列化
        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        var jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(om,Object.class);
        return jackson2JsonRedisSerializer;
    }

    private int randomTTL(){
        return ThreadLocalRandom.current().nextInt(1000 * 60 * 5);
    }
}
